package com.haoqizhe.kernel.security.config;

import cn.hutool.core.util.StrUtil;
import com.haoqizhe.kernel.security.properties.SecuritySetting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
 * security 配置
 * @EnableWebSecurity 开启web security认证
 * @EnableGlobalMethodSecurity 开启security 注解式接口方法级认证
 * @Order 设置securityConfig的加载顺序
 * @author haoqizhe.li
 * @date 2018/10/13
 **/
@EnableWebSecurity
@Slf4j
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.DEFAULT_FILTER_ORDER)
@EnableConfigurationProperties(SecuritySetting.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    @Autowired
    private SecuritySetting setting;
    @Autowired
    private UserDetailsService userDetailsServiceImpl;
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.cors().configurationSource(corsConfigurationSource())
                .and().csrf().disable()
                /**
                 * 登录处理
                 */
                .addFilter(new JwtAuthenticationFilter(authenticationManager(),setting.getProcessesUrl()))
                /**
                 * 请求校验token处理
                 */
                .addFilter(new JwtAuthorizationFilter(authenticationManager()))
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint())
                /**
                 * 无权限拦截处理
                 */
                .accessDeniedHandler(myAccessDeniedHandler);
        /**
         * 设置无限制访问的链接，多个逗号分隔
         */
        if(StrUtil.isNotBlank(setting.getPermitAll())){
            http.authorizeRequests().antMatchers(setting.getPermitAll().split(",")).permitAll();
        }
        /**
         * 设置限制访问的链接，多个逗号分隔
         */
        if(StrUtil.isNotBlank(setting.getAuthenticated())){
            http.authorizeRequests().antMatchers(setting.getAuthenticated().split(",")).authenticated();
        }
        /**
         * 设置退出登录地址，默认为logout
         */
        if(StrUtil.isNotBlank(setting.getLogoutUrl())){
            http.logout().logoutUrl(setting.getLogoutUrl()).permitAll();
        }
        /**
         * 成功退出登录地址
         */
        if(setting.getLogoutHandler()){
            http.logout().logoutSuccessHandler(myLogoutSuccessHandler);
        }
        if(StrUtil.isNotBlank(setting.getLogoutSuccessUrl())){
            http.logout().logoutSuccessUrl(setting.getLogoutSuccessUrl()).permitAll();
        }
    }

    @Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder
                .userDetailsService(userDetailsServiceImpl)
                .passwordEncoder(new BCryptPasswordEncoder());
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }
}
